package com.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dao.ShoufeixinxiDao;
import com.entity.ShoufeixinxiEntity;
import com.entity.excel.ShoufeixinxiExcel;
import com.entity.view.ShoufeixinxiView;
import com.entity.view.ZhichuxinxiView;
import com.excel.ExcelConstants;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.service.ShoufeixinxiService;
import com.utils.PageUtils;
import com.utils.Query;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 收费信息 服务实现类
 */
@Service("shoufeixinxiService")
@Transactional
public class ShoufeixinxiServiceImpl extends ServiceImpl<ShoufeixinxiDao, ShoufeixinxiEntity> implements ShoufeixinxiService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        if (params != null && (params.get("limit") == null || params.get("page") == null)) {
            params.put("page", "1");
            params.put("limit", "10");
        }
        Page<ShoufeixinxiView> page = new Page<>();

        PageHelper.startPage(Integer.parseInt(params.get("page").toString()), Integer.parseInt(params.get("limit").toString()));
        PageInfo<ShoufeixinxiView> shoufeixinxiViewPageInfo = new PageInfo<>(baseMapper.selectListView(page, params));
        page.setTotal(shoufeixinxiViewPageInfo.getTotal());
        page.setRecords(shoufeixinxiViewPageInfo.getList());
        page.setCurrent(shoufeixinxiViewPageInfo.getPageNum());
        page.setSize(shoufeixinxiViewPageInfo.getPageSize());
        page.setPages(shoufeixinxiViewPageInfo.getPages());
        return new PageUtils(page);
    }

    @Override
    public void export() throws IOException {
        if (false) {
            exportShenDuPage();
        } else {

            OutputStream outputStream = null;
            try {
                //记录总数:实际中需要根据查询条件进行统计即可
                Long totalLong = baseMapper.selectCount(null);
                //long转int
                Integer totalCount = totalLong.intValue();
                //每一个Sheet存放10w条数据
                Integer sheetDataRows = ExcelConstants.PER_SHEET_ROW_COUNT;
                //每次写入的数据量10w,每页查询10W
                Integer writeDataRows = ExcelConstants.PER_WRITE_ROW_COUNT;
                //计算需要的Sheet数量
                Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);
                //计算一般情况下每一个Sheet需要写入的次数(一般情况不包含最后一个sheet,因为最后一个sheet不确定会写入多少条数据)
                Integer oneSheetWriteCount = sheetDataRows / writeDataRows;
                //计算最后一个sheet需要写入的次数
                Integer lastSheetWriteCount = totalCount % sheetDataRows == 0 ? oneSheetWriteCount : (totalCount % sheetDataRows % writeDataRows == 0 ? (totalCount / sheetDataRows / writeDataRows) : (totalCount / sheetDataRows / writeDataRows + 1));

                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletResponse response = requestAttributes.getResponse();
                outputStream = response.getOutputStream();
                //必须放到循环外，否则会刷新流
                ExcelWriter excelWriter = EasyExcel.write(outputStream).build();

                //开始分批查询分次写入
                for (int i = 0; i < sheetNum; i++) {
                    //创建Sheet
                    WriteSheet sheet = new WriteSheet();
                    sheet.setSheetName("第" + i + "批");
                    sheet.setSheetNo(i);
                    //循环写入次数: j的自增条件是当不是最后一个Sheet的时候写入次数为正常的每个Sheet写入的次数,如果是最后一个就需要使用计算的次数lastSheetWriteCount
                    for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
                        //分页查询一次10w
                        PageHelper.startPage(j + 1 + oneSheetWriteCount * i, writeDataRows);
                        List<ShoufeixinxiEntity> empList = baseMapper.selectList(null);
                        List<ShoufeixinxiExcel> empVoList = new ArrayList<>();
                        for (ShoufeixinxiEntity emp : empList) {
                            ShoufeixinxiExcel empVo = new ShoufeixinxiExcel();
                            BeanUtils.copyProperties(emp, empVo);
                            empVoList.add(empVo);
                        }
                        WriteSheet writeSheet = EasyExcel.writerSheet(i, "员工信息" + (i + 1)).head(ShoufeixinxiExcel.class)
                                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                        //写数据
                        excelWriter.write(empVoList, writeSheet);
                    }
                }
                // 下载EXCEL
                response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
                response.setCharacterEncoding("utf-8");
                // 这里URLEncoder.encode可以防止浏览器端导出excel文件名中文乱码 当然和easyexcel没有关系
                String fileName = URLEncoder.encode("收费信息", "UTF-8").replaceAll("\\+", "%20");
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
                excelWriter.finish();
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (BeansException e) {
                e.printStackTrace();
            } finally {
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        }

    }

    public void exportShenDuPage() throws IOException {
        OutputStream outputStream = null;
        try {
            //记录总数:实际中需要根据查询条件进行统计即可
            Long totalLong = baseMapper.selectCount(null);
            //long转int
            Integer totalCount = totalLong.intValue();
            //每一个Sheet存放10w条数据
            Integer sheetDataRows = ExcelConstants.PER_SHEET_ROW_COUNT;
            //每次写入的数据量10w,每页查询10W
            Integer writeDataRows = ExcelConstants.PER_WRITE_ROW_COUNT;
            //计算需要的Sheet数量
            Integer sheetNum = totalCount % sheetDataRows == 0 ? (totalCount / sheetDataRows) : (totalCount / sheetDataRows + 1);
            //计算一般情况下每一个Sheet需要写入的次数(一般情况不包含最后一个sheet,因为最后一个sheet不确定会写入多少条数据)
            Integer oneSheetWriteCount = sheetDataRows / writeDataRows;
            //计算最后一个sheet需要写入的次数
            Integer lastSheetWriteCount = totalCount % sheetDataRows == 0 ? oneSheetWriteCount : (totalCount % sheetDataRows % writeDataRows == 0 ? (totalCount / sheetDataRows / writeDataRows) : (totalCount / sheetDataRows / writeDataRows + 1));

            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletResponse response = requestAttributes.getResponse();
            outputStream = response.getOutputStream();
            //必须放到循环外，否则会刷新流
            ExcelWriter excelWriter = EasyExcel.write(outputStream).build();

            //开始分批查询分次写入
            //最后一个id，深度使用
            int lastId = 0;
            for (int i = 0; i < sheetNum; i++) {
                //创建Sheet
                WriteSheet sheet = new WriteSheet();
                sheet.setSheetName("第" + i + "批");
                sheet.setSheetNo(i);
                //循环写入次数: j的自增条件是当不是最后一个Sheet的时候写入次数为正常的每个Sheet写入的次数,如果是最后一个就需要使用计算的次数lastSheetWriteCount
                for (int j = 0; j < (i != sheetNum - 1 ? oneSheetWriteCount : lastSheetWriteCount); j++) {
                    //深度查询
                    Map<String,Object> params = new HashMap<>();
                    params.put("id",lastId);
                    params.put("pageSize",writeDataRows);
                    List<ShoufeixinxiView> shoufeixinxiViews = baseMapper.selectShenDU(params);
                    //获取最后一个id
                    lastId = shoufeixinxiViews.get(shoufeixinxiViews.size() - 1).getId();
                    List<ShoufeixinxiExcel> shoufeixinxiExcels = new ArrayList<>();
                    for (ShoufeixinxiEntity shoufeixinxi : shoufeixinxiViews) {
                        ShoufeixinxiExcel shoufeixinxiExcel = new ShoufeixinxiExcel();
                        BeanUtils.copyProperties(shoufeixinxi, shoufeixinxiExcel);
                        shoufeixinxiExcels.add(shoufeixinxiExcel);
                    }
                    WriteSheet writeSheet = EasyExcel.writerSheet(i, "员工信息" + (i + 1)).head(ShoufeixinxiExcel.class)
                            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                    //写数据
                    excelWriter.write(shoufeixinxiExcels, writeSheet);
                }
            }
            // 下载EXCEL
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止浏览器端导出excel文件名中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("收费信息", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            excelWriter.finish();
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (BeansException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }


}
